/*   
 * Copyright (C) 2015 O. Wu
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.osx.my2048.view;

import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import org.osx.my2048.util.Util;
import org.osx.my2048.util.State;

/**
 * The main frame of 2048 game.
 * 
 * @author O. Wu
 * @date 15/02/18
 */
public class GameBoard extends JFrame {

	private static final long serialVersionUID = -9198028534149596556L;

	public static final int BLOCK_PER_LINE = 4;

	public static final int LENGTH = BLOCK_PER_LINE * BLOCK_PER_LINE;

	public static final int TARGET_VALUE = 2048;
	
	public static final double SCALE_OF_GENERATE_VALUE_FOUR = 0.4;

	private List<Block> blockMatrix;

	/** The current state of the game. */
	private State state = State.MOVEABLE;

	public List<Block> getBlock() {
		return blockMatrix;
	}

	public State state() {
		return state;
	}

	public GameBoard() {
		this.setTitle("2048");
		this.setSize(400, 400);
		this.setLocationRelativeTo(null);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setResizable(false);

		JPanel panel = new JPanel(new GridLayout(BLOCK_PER_LINE,
				BLOCK_PER_LINE, 5, 5));

		// add some block into the block matrix list
		blockMatrix = new ArrayList<Block>();
		for (int i = 0; i < LENGTH; i++) {
			blockMatrix.add((Block) panel.add(new Block()));
		}

		// set 2 blocks visible (randomly)
		showMoveableBlock(2);

		this.setContentPane(panel);
		this.addKeyListener(new GameBoardListener(this));
	}

	public void showMoveableBlock(int numOfBlock) {
		int size = LENGTH;
		for (int i = 0; i < numOfBlock; i++) {
			Block b = blockMatrix.get(0);
			while (b.value() != 0) {
				b = blockMatrix.get((int) (Math.random() * size));
			}
			b.setValue((Math.random() < SCALE_OF_GENERATE_VALUE_FOUR) ? 4 : 2);
		}
	}

	public void checkGameState(int[] stateArray) {
		int sumZero = 0;

		for (int i = 0; i < stateArray.length; i++) {
			if (stateArray[i] == 0) {
				sumZero++;
			}
			if (stateArray[i] == TARGET_VALUE) {
				state = State.WIN;
			}
			blockMatrix.get(i).setValue(stateArray[i]);
		}

		if (sumZero == 0 && state != State.WIN) {
			boolean merge = Util.mergeAvaliable(stateArray, BLOCK_PER_LINE);
			state = (!merge) ? State.LOSE : state;
		}
	}

	public void activateGameEvent(Object message) {
		JOptionPane.showMessageDialog(GameBoard.this, message, "Message",
				JOptionPane.INFORMATION_MESSAGE);
//		blockMatrix.forEach(n -> n.setValue(0));
		
		for( Block n: blockMatrix){
			n.setValue(0);
		}
		state = State.MOVEABLE;
		showMoveableBlock(2);
	}
}
